package com.elight.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
		
	static final int BUFFER = 8192;

	/**
	 * 压缩文件
	 * 
	 * @param srcPathName
	 * 		要压缩的目录
	 * @param zipFile
	 * 		生成的文件名
	 * @throws Exception 
	 */	    
	public static void zip(String srcPathName, String zipFile){
		File file = new File(srcPathName);
		if (!file.exists()) {
			System.out.println("目录不存在");
		}
		try {
			FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
			CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,new CRC32());
			ZipOutputStream out = new ZipOutputStream(cos);
			String basedir = "";
			compressByType(file, out, basedir);
			out.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 解压缩zip文件
	 * @param zipFilePath zip文件的全路径
	 * @param unzipFilePath 解压后文件保存的路径
	 */
	@SuppressWarnings("rawtypes")
	public static void unzip(String zipFilePath,String unzipFilePath){
		  try {
	            ZipFile zipFile = new ZipFile(zipFilePath);
	            Enumeration emu = zipFile.entries();
	            while(emu.hasMoreElements()){
	                ZipEntry entry = (ZipEntry)emu.nextElement();
	                //会把目录作为一个file读出一次，所以只建立目录就可以，之下的文件还会被迭代到。
	                if (entry.isDirectory())
	                {
	                    new File(unzipFilePath + entry.getName()).mkdirs();
	                    continue;
	                }
	                BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
	                File file = new File(unzipFilePath + entry.getName());
	                //加入这个的原因是zipfile读取文件是随机读取的，这就造成可能先读取一个文件
	                //而这个文件所在的目录还没有出现过，所以要建出目录来。
	                File parent = file.getParentFile();
	                if(parent != null && (!parent.exists())){
	                    parent.mkdirs();
	                }
	                FileOutputStream fos = new FileOutputStream(file);
	                BufferedOutputStream bos = new BufferedOutputStream(fos,BUFFER);           
	                
	                int count;
	                byte data[] = new byte[BUFFER];
	                while ((count = bis.read(data, 0, BUFFER)) != -1)
	                {
	                    bos.write(data, 0, count);
	                }
	                bos.flush();
	                bos.close();
	                bis.close();
	            }
	            zipFile.close();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	}

	/**
	 * 判断是目录还是文件，根据类型（文件/文件夹）执行不同的压缩方法
	 * 
	 * @param file
	 * @param out
	 * @param basedir
	 */
	private static void compressByType(File file, ZipOutputStream out,String basedir) {
		/* 判断是目录还是文件 */
		if (file.isDirectory()) {
			// logger.info("压缩：" + basedir + file.getName());
			compressDirectory(file, out, basedir);
		} else {
			// logger.info("压缩：" + basedir + file.getName());
			compressFile(file, out, basedir);
		}
	}

	/**
	 * 压缩一个目录
	 * 
	 * @param dir
	 * @param out
	 * @param basedir
	 */
	private static void compressDirectory(File dir, ZipOutputStream out,String basedir) {
		if (!dir.exists()) {
			return;
		}

		File[] files = dir.listFiles();
		for (int i = 0; i < files.length; i++) {
			/* 递归 */
			compressByType(files[i], out, basedir + dir.getName() + "/");
		}
	}

	/**
	 * 压缩一个文件
	 * 
	 * @param file
	 * @param out
	 * @param basedir
	 */
	private static void compressFile(File file, ZipOutputStream out,String basedir) {
		if (!file.exists()) {
			return;
		}
		try {
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			ZipEntry entry = new ZipEntry(basedir + file.getName());
			out.putNextEntry(entry);
			int count;
			byte data[] = new byte[BUFFER];
			while ((count = bis.read(data, 0, BUFFER)) != -1) {
				out.write(data, 0, count);
			}
			bis.close();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}